package org.ehe.ai.service;


import com.alibaba.dashscope.app.Application;
import com.alibaba.dashscope.app.ApplicationResult;
import com.alibaba.dashscope.exception.ApiException;
import com.alibaba.dashscope.exception.InputRequiredException;
import com.alibaba.dashscope.exception.NoApiKeyException;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.ehe.ai.domain.ChatAccessLog;
import org.ehe.ai.domain.ChatMessage;
import org.ehe.ai.domain.ChatSession;
import org.ehe.ai.domain.dto.ChatRequest;
import org.ehe.ai.domain.dto.ChatResponse;
import org.ehe.ai.mapper.ChatAccessLogMapper;
import org.ehe.ai.mapper.ChatMessageMapper;
import org.ehe.ai.mapper.ChatSessionMapper;
import org.ehe.common.core.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.dashscope.app.ApplicationParam;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
/**
 * @author :zhangnn
 * @className :ChatService
 * @description: TODO
 * @date 2025-08-23 09:15:47
 */

@Slf4j
@Service
public class ChatService {
    @Autowired
    private ChatSessionMapper chatSessionMapper;

    @Autowired
    private ChatMessageMapper chatMessageMapper;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private ChatAccessLogMapper accessLogMapper;

    @Value("${aliyun.dashscope.apiKey}")
    private  String API_KEY;
    @Value("${aliyun.dashscope.appId}")
    private  String APP_ID;


    private static final String REDIS_SESSION_PREFIX = "chat:session:";
    private static final String REDIS_MESSAGES_PREFIX = "chat:messages:";

    /**
     * 调用AI API（公共方法，供流式服务使用）
     */
    public String callAiApi(String prompt) throws ApiException, NoApiKeyException, InputRequiredException {
        ApplicationParam param = ApplicationParam.builder()
            .apiKey(API_KEY)
            .appId(APP_ID)
            .prompt(prompt)
            .build();

        Application application = new Application();
        ApplicationResult result = application.call(param);

        return result.getOutput().getText();
    }

    /**
     * 保存消息到数据库（公共方法，供流式服务使用）
     */
    public void saveMessage(String sessionId, String content, int messageType) {
        ChatMessage message = new ChatMessage()
            .setSessionId(sessionId)
            .setMessageType(messageType)
            .setContent(content)
            .setCreateTime(new Date())
            .setModelName("dashscope");

        chatMessageMapper.insert(message);
        log.info("消息已保存到数据库，会话ID: {}, 消息类型: {}", sessionId, messageType);

        // 删除Redis中的消息列表缓存（下次读取时自动从数据库加载最新数据）
        String cacheKey = REDIS_MESSAGES_PREFIX + sessionId;
        redisTemplate.delete(cacheKey);
        log.info("消息缓存已删除，会话ID: {}", sessionId);
    }

    /**
     * 验证会话是否存在，不存在则创建
     */
    public String validateOrCreateSession(String sessionId, String userId) {
        if (sessionId == null || sessionId.isEmpty()) {
            return createSession(userId,sessionId);
        }
        // 验证会话是否存在
        ChatSession session = chatSessionMapper.selectOne(new LambdaQueryWrapper<ChatSession>()
            .eq(ChatSession::getSessionId,sessionId));
        if (session == null) {
            log.warn("会话不存在，创建新会话: {}", sessionId);
            return createSession(userId,sessionId);
        }

        return sessionId;
    }

    /**
     * 创建新会话
     */
    public String createSession(String userId,String sessionId) {
        if(StringUtils.isBlank(sessionId)){
            sessionId = java.util.UUID.randomUUID().toString().replace("-", "");

        }
        ChatSession session = new ChatSession()
            .setSessionId(sessionId)
            .setUserId(userId)
            .setTitle("新的对话")
            .setCreateTime(new Date())
            .setUpdateTime(new Date())
            .setStatus(1);

        chatSessionMapper.insert(session);

        log.info("新会话已创建: {}", sessionId);
        // 缓存会话信息
        redisTemplate.opsForValue().set(
            REDIS_SESSION_PREFIX + sessionId,
            session,
            24,
            TimeUnit.HOURS
        );

        return sessionId;
    }

    /**
     * 发送消息并获取AI回复
     */
    @Transactional
    public ChatResponse sendMessage(ChatRequest request, HttpServletRequest httpRequest) {
        long startTime = System.currentTimeMillis();
        ChatResponse response = new ChatResponse();

        try {
            // 验证或创建会话
            String sessionId = request.getSessionId();
            if (sessionId == null || sessionId.isEmpty()) {
                sessionId = createSession(request.getUserId(),request.getSessionId());
            }
            // 保存用户消息
            saveMessage(sessionId, request.getMessage(), 1);
            // 调用AI API
            String aiResponse = callAiApi(request.getMessage());
            // 保存AI回复
            saveMessage(sessionId, aiResponse, 2);
            // 更新会话标题（使用消息前30字符）
            updateSessionTitle(sessionId, request.getMessage());

            // 构建响应
            response.setSessionId(sessionId);
            response.setMessage(aiResponse);
            response.setTimestamp(LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            response.setSuccess(true);

            // 记录访问日志
            logAccess(request, response, httpRequest, System.currentTimeMillis() - startTime);

        } catch (Exception e) {
            log.error("处理聊天消息失败", e);
            response.setSuccess(false);
            response.setErrorMessage(e.getMessage());
        }

        return response;
    }

    /**
     * 获取会话历史消息
     */
    public List<ChatMessage> getSessionMessages(String sessionId) {
        // 先尝试从Redis获取
        String cacheKey = REDIS_MESSAGES_PREFIX + sessionId;
        List<ChatMessage> messages = (List<ChatMessage>) redisTemplate.opsForValue().get(cacheKey);

        //if (messages == null) {
            // 从数据库查询
            QueryWrapper<ChatMessage> wrapper = new QueryWrapper<>();
            wrapper.eq("session_id", sessionId).orderByAsc("create_time");
            messages = chatMessageMapper.selectList(wrapper);

            // 缓存消息列表
            if (!messages.isEmpty()) {
                redisTemplate.opsForValue().set(cacheKey, messages, 1, TimeUnit.HOURS);
            }
        //}
        return messages;
    }

    /**
     * 获取用户的会话列表
     */
    public List<ChatSession> getUserSessions(String userId) {
        QueryWrapper<ChatSession> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId).eq("status", 1).orderByDesc("update_time").last(" limit 20");
        return chatSessionMapper.selectList(wrapper);
    }
    /**
     * 删除会话
     */
    @Transactional
    public boolean deleteSession(String sessionId, String userId) {
        try {
            // 软删除会话
            QueryWrapper<ChatSession> wrapper = new QueryWrapper<>();
            wrapper.eq("session_id", sessionId).eq("user_id", userId);

            ChatSession session = new ChatSession();
            session.setStatus(0); // 标记为删除
            session.setUpdateTime(new Date());

            int updated = chatSessionMapper.update(session, wrapper);

            if (updated > 0) {
                // 清除Redis缓存
                redisTemplate.delete(REDIS_SESSION_PREFIX + sessionId);
                redisTemplate.delete(REDIS_MESSAGES_PREFIX + sessionId);

                log.info("会话已删除: {}", sessionId);
                return true;
            }

            return false;
        } catch (Exception e) {
            log.error("删除会话失败: {}", sessionId, e);
            return false;
        }
    }
    /**
     * 记录访问日志
     */
    private void logAccess(ChatRequest request, ChatResponse response,
                           HttpServletRequest httpRequest, long responseTime) {
        try {
            ChatAccessLog log = new ChatAccessLog()
                .setSessionId(request.getSessionId())
                .setUserId(request.getUserId())
                .setRequestContent(request.getMessage())
                .setResponseContent(response.getMessage())
                .setIpAddress(getClientIpAddress(httpRequest))
                .setUserAgent(httpRequest.getHeader("User-Agent"))
                .setResponseTime((int) responseTime)
                .setApiCost(BigDecimal.valueOf(0.001)) // 示例成本
                .setCreateTime(new Date());

            accessLogMapper.insert(log);
        } catch (Exception e) {
            log.error("记录访问日志失败", e);
        }
    }

    /**
     * 获取客户端真实IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
            return xForwardedFor.split(",")[0];
        }

        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
            return xRealIp;
        }

        return request.getRemoteAddr();
    }

    /**
     * 更新会话标题
     */
    public void updateSessionTitle(String sessionId, String firstMessage) {
      String title = firstMessage.length() > 30 ?
            firstMessage.substring(0, 30) + "..." : firstMessage;

        ChatSession session = new ChatSession()
            .setSessionId(sessionId)
            .setTitle(title)
            .setUpdateTime(new Date());

        QueryWrapper<ChatSession> wrapper = new QueryWrapper<>();
        wrapper.eq("session_id", sessionId);
        chatSessionMapper.update(session, wrapper);

        // 同步更新Redis缓存（先查最新数据再更新）
        ChatSession updatedSession = chatSessionMapper.selectOne(wrapper);
        if (updatedSession != null) {
            redisTemplate.opsForValue().set(
                REDIS_SESSION_PREFIX + sessionId,
                updatedSession,
                24,
                TimeUnit.HOURS
            );
            log.info("会话缓存已更新，会话ID: {}", sessionId);
        }
    }


    /**
     * 清理过期缓存
     */
    public void cleanupExpiredCache() {
        log.info("开始清理过期缓存...");
        long startTime = System.currentTimeMillis();
        int sessionCacheCount = 0;
        int messageCacheCount = 0;

        try {
            // 清理会话相关过期缓存
            Set<Object> sessionKeys = Collections.singleton(redisTemplate.keys(REDIS_SESSION_PREFIX + "*"));
            if (sessionKeys != null && !sessionKeys.isEmpty()) {
                for (Object key : sessionKeys) {
                    String keyStr = key.toString();
                    // 检查缓存是否已过期
                    Boolean hasKey = redisTemplate.hasKey(keyStr);
                    if (Boolean.FALSE.equals(hasKey)) {
                        redisTemplate.delete(keyStr);
                        sessionCacheCount++;
                        log.debug("清理过期会话缓存: {}", keyStr);
                    } else {
                        // 可选：对于长期未更新的缓存主动过期（例如超过7天）
                        Long ttl = redisTemplate.getExpire(keyStr, TimeUnit.DAYS);
                        if (ttl != null && ttl < 0) { // 永不过期的缓存
                            redisTemplate.expire(keyStr, 7, TimeUnit.DAYS);
                            log.debug("为永不过期会话缓存设置过期时间: {}", keyStr);
                        }
                    }
                }
            }

            // 清理消息相关过期缓存
            Set<Object> messageKeys = Collections.singleton(redisTemplate.keys(REDIS_MESSAGES_PREFIX + "*"));
            if (messageKeys != null && !messageKeys.isEmpty()) {
                for (Object key : messageKeys) {
                    String keyStr = key.toString();
                    Boolean hasKey = redisTemplate.hasKey(keyStr);
                    if (Boolean.FALSE.equals(hasKey)) {
                        redisTemplate.delete(keyStr);
                        messageCacheCount++;
                        log.debug("清理过期消息缓存: {}", keyStr);
                    } else {
                        // 可选：消息缓存超过24小时强制过期
                        Long ttl = redisTemplate.getExpire(keyStr, TimeUnit.HOURS);
                        if (ttl != null && ttl > 24) {
                            redisTemplate.expire(keyStr, 24, TimeUnit.HOURS);
                            log.debug("调整消息缓存过期时间: {}", keyStr);
                        }
                    }
                }
            }

            long endTime = System.currentTimeMillis();
            log.info("缓存清理完成 - 清理会话缓存: {} 个, 清理消息缓存: {} 个, 耗时: {}ms",
                sessionCacheCount, messageCacheCount, (endTime - startTime));
        } catch (Exception e) {
            log.error("清理过期缓存失败", e);
        }
    }

    public int countChatMessage(String sessionId) {
        List<ChatMessage> chatMessages = chatMessageMapper.selectList(new LambdaQueryWrapper<ChatMessage>()
            .eq(ChatMessage::getSessionId, sessionId)
            .eq(ChatMessage::getMessageType, 1));

        return chatMessages.size();

    }

    public ChatSession selectSession(String sessionId) {
        QueryWrapper<ChatSession> wrapper = new QueryWrapper<>();
        wrapper.eq("session_id", sessionId);
        // 同步更新Redis缓存（先查最新数据再更新）
        ChatSession session = chatSessionMapper.selectOne(wrapper);
        return session;
    }
}
